1 /*
2 Copyright: Marcelo S. N. Mancini, 2018 - 2021
3 License:   [https://opensource.org/licenses/MIT|MIT License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the MIT Software License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://opensource.org/licenses/MIT)
10 */
11 
12 module hip.event.handlers.keyboard;
13 
14 import hip.event.handlers.keyboard_layout;
15 public import hip.event.handlers.button;
16 public import hip.api.input.keyboard;
17 
18 import hip.util.data_structures;
19 import hip.error.handler;
20 import hip.util.time, hip.util.array;
21 
22 char toUppercase(char a)
23 {
24     ubyte charV = ubyte(a);
25     if(charV >= HipKey.A+32 && charV <= HipKey.Z+32)
26         return cast(char)(charV-32);
27     return a;
28 }
29 
30 
31 
32 
33 /** 
34  *  This class controls callbacks related to keyboard buttons state, as its downtime, uptime,
35  *  its current state, modifier key states and callbacks assigned to specific keys.
36  *
37  *  Controls what text has been typed in the current frame, useful for Label or Text objects.
38  */
39 class KeyboardHandler : IHipKeyboard
40 {
41     private __gshared int[256] pressedKeys;
42     private __gshared HipButtonMetadata[256] metadatas;
43     private __gshared string frameText;
44 
45     private __gshared bool altPressed;
46     private __gshared bool shiftPressed;
47     private __gshared bool ctrlPressed;
48     private __gshared float keyRepeatDelay = 0.5;
49 
50     this()
51     {
52         if(metadatas[0] is null)
53         {
54             for(int i = 0; i < 256; i++)
55                 metadatas[i] = new HipButtonMetadata(i);
56             pressedKeys[] = 0;
57         }
58     }
59     
60 
61     /**
62     * Takes care of the pressed keys array
63     */
64     private void setPressed(HipKey key, bool press)
65     {
66         ubyte Key = cast(ubyte)key;
67         metadatas[Key].setPressed(press);
68         if(press)
69         {
70             if(pressedKeys.indexOf(Key) == -1)
71             {
72                 pressedKeys[pressedKeys.indexOf(0)] = Key; //Assign to null index a key
73             }
74         }
75         else
76         {
77             const int index = pressedKeys.indexOf(0); //Get last index
78             const int upIndex = pressedKeys.indexOf(Key);
79             if(index > 1)
80             {
81                 swapAt(pressedKeys, index - 1, upIndex);//Swaps the current key with the last valid key
82                 pressedKeys[index - 1] = 0;
83             }
84             else pressedKeys[0] = 0;
85         }
86         switch(key)
87         {
88             case HipKey.ALT:
89                 altPressed = press;
90                 break;
91             case HipKey.CTRL:
92                 ctrlPressed = press;
93                 break;
94             case HipKey.SHIFT:
95                 shiftPressed = press;
96                 break;
97             default:
98                 break;
99         }
100 
101     }
102 
103     void handleKeyUp(HipKey key)
104     {
105         setPressed(key, false);
106     }
107     AHipButtonMetadata getMetadata(char key) const {return metadatas[key];}
108 
109     bool isKeyPressed(char key){return metadatas[key]._isPressed;}
110     bool isKeyJustPressed(char key){return metadatas[key].isJustPressed;}
111     bool isKeyJustReleased(char key){return metadatas[key].isJustReleased;}
112     float getKeyDownTime(char key){return metadatas[key].getDownTimeDuration();}
113     float getKeyUpTime(char key){return metadatas[key].getUpTimeDuration();}
114 
115     
116     /**
117     *   Updates the metadata
118     */
119     void handleKeyDown(HipKey key)
120     {
121         setPressed(key, true);
122         // import hip.console.log;
123         // logln("Set pressed the key ", key);
124     }
125     
126     static string getInputText(KeyboardLayout layout)
127     {
128         KeyboardLayout.KeyState state = KeyboardLayout.KeyState.NONE;
129         if(altPressed)
130             state|= KeyboardLayout.KeyState.ALT;
131         if(shiftPressed)
132             state|= KeyboardLayout.KeyState.SHIFT;
133         if(ctrlPressed)
134             state|= KeyboardLayout.KeyState.CTRL;
135         string ret = "";
136         int i = 0;
137         while(pressedKeys[i] != 0)
138         {
139             const float pressTime = metadatas[pressedKeys[i]].getDownTimeDuration();
140             if(pressTime >= keyRepeatDelay || metadatas[pressedKeys[i]]._isNewState)
141                 ret~= layout.getKey(toUppercase(cast(char)pressedKeys[i]), state);
142             i++;
143         }
144         return ret;
145     }
146 
147     void update()
148     {
149     }
150 
151     void postUpdate()
152     {
153         for(int i = 0; i < metadatas.length; i++)
154             metadatas[i]._isNewState = false;
155         frameText = "";
156     }
157 
158 }